package org.dormi.learn.domain;

import org.dormi.learn.event.BaseEvent;
import org.dormi.learn.exp.CatalogedException;
import org.dormi.learn.pojo.BaseEO;
import org.dormi.learn.utils.TrackingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 领域方法
 *
 * @param <INPUT> 上下文(输入), 这个是可以进行更改的
 * @author : dormi330
 * @version : 1.0
 */
public abstract class AbstractDomainAction<INPUT extends BaseEO> implements DomainMethod {

    /** 状态 */
    private enum ActionStatus {
        NOT_START,
        STARTED,
        OVER
    }

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    // 内部变量
    private ActionStatus _status = ActionStatus.NOT_START;  // 是否已经结束

    // input
    protected INPUT input;

    // output
    protected List<BaseEvent> events;
    protected RuntimeException exp;

    /* === constructor === */
    /* === constructor === */
    /* === constructor === */

    /**
     * constructor
     *
     * @param input 输入EPO
     */
    public AbstractDomainAction(INPUT input) {
        this.input = input;
    }

    /* === process === */
    /* === process === */
    /* === process === */

    @Override
    public List<BaseEvent> getEvents() {
        return events;
    }

    @Override
    public void beforeProcess() {
    }

    @Override
    public void afterProcess() {
    }

    public final boolean process() {
        TrackingUtils.debugTrace();

        if (_status == ActionStatus.STARTED || _status == ActionStatus.OVER) {
            throw new RuntimeException("action不能启动, 当前状态=" + _status);
        }

        try {
            _status = ActionStatus.STARTED;
            beforeProcess();
            _processInternal();
            afterProcess();
        } catch (Exception ex) {
            exp = new RuntimeException(ex);
            ex.printStackTrace();
        }
        _status = ActionStatus.OVER;

        return exp == null;
    }

    /** 不要手动调用此方法 */
    protected abstract void _processInternal() throws CatalogedException;

    /**
     * 添加领域事件
     *
     * @param e 领域事件
     */
    protected void addEvent(BaseEvent e) {
        if (e == null) {
            return;
        }
        if (events == null) {
            events = new ArrayList<>(1);
        }
        events.add(e);
    }

    /* === set/get === */
    /* === set/get === */
    /* === set/get === */

    public INPUT getInput() {
        return input;
    }

    protected void setDomainEvents(List<BaseEvent> events) {
        this.events = events;
    }

    public RuntimeException getExp() {
        return exp;
    }

    protected void setExp(RuntimeException exp) {
        this.exp = exp;
    }
}
